package com.jwdemo
{
	// Simple Bezier Object - with support functions for 
	// calculating a curves length.
	
	import com.jwdemo.RenderHelper;

	public class Bezier
	{
		private var _cp0:Vector2 ;
		private var _cp1:Vector2 ;
		private var _cp2:Vector2 ;
		private var _cp3:Vector2 ;
		private var _vCP:Vector2 ;

		private var _cx:Number ;
		private var _bx:Number ;
		private var _ax:Number ;

		private var _cy:Number ;
		private var _by:Number ;
		private var _ay:Number ;

		private var _length:Number = 0.0;
		
		public function Bezier(cp0:Vector2, cp1:Vector2, cp2:Vector2, cp3:Vector2)
		{
			this._cp0		=	cp0 ;
			this._cp1		=	cp1 ;
			this._cp2		=	cp2 ;
			this._cp3		=	cp3 ;
			
			this._vCP		=	new Vector2(cp0) ;

			this._cx		=	3.0 * (cp1.X() - cp0.X()) ; 
			this._bx		=	3.0 * (cp2.X() - cp1.X()) - this._cx ; 
			this._ax		=	cp3.X() - cp0.X() - this._cx - this._bx ;
			this._cy		=	3.0 * (cp1.Y() - cp0.Y()) ;
			this._by		=	3.0 * (cp2.Y() - cp1.Y()) - this._cy ;
			this._ay		=	cp3.Y() - cp0.Y() - this._cy - this._by ;
			this._length	=	this.calcLength() ;	 

		}
		
		public function getLength() : Number 
		{
			return this._length ;
		}
		
		public function getVectorPosition(t:Number):Vector2
		{
			var pos:Object = this.getPositionXY(t) ;
			return new Vector2(pos) ;	
		}
		
		public function getPositionXY(t:Number) : Object
		{
			var tSquared:Number		=	t * t ;
			var tCubed:Number		=	tSquared * t ;
			
			var resultx:Number		=	(this._ax * tCubed) + (this._bx * tSquared) + (this._cx * t) + this._vCP.X() ;
			var resulty:Number		=	(this._ay * tCubed) + (this._by * tSquared) + (this._cy * t) + this._vCP.Y() ;

			return {x: resultx , y: resulty } ;
			
		}

		// Calculate Srt(x'(t)^2 + y'(t)^2)
		//x'(t),y'(t) is d/dt of x(t), y(t) - (Bezier defn getPositionXY(t))
		private function getPrimeT(tv:Number) : Number
		{
			
			var	t				=	tv ? tv : 1 ;
			var tSquared		=	t * t ;

			// work out dx/dt and dy/dt    
			
			var resultx:Number 	= 	(3*this._ax * tSquared) + (2*this._bx * t) + (this._cx) ;
			var resulty:Number  =	(3*this._ay * tSquared) + (2*this._by * t) + (this._cy) ;
			
			return Math.sqrt(resultx*resultx + resulty*resulty)	;
		}
		
		private function calcLength(fft : Number) : Number
		{
			var ft:Number	=	fft	? fft : 1 ;
			
			//Integrate using Trapezium rule
			var N:int	 		= 	100 ;
			var n:int	 	 	=	parseInt(ft*N) ; //Math.floor(ft*N) ;
			var dt:Number 		=	1/N //0.01 == one hundred bits ;
			
			var sum1:Number 	=	(this.getPrimeT(0) + this.getPrimeT(ft))/(2*n) ;
			var sum:Number		=	0 ;
			//			for t = dt,ft - dt, dt do
			//				sum	=	sum	+	 this.GetPrimeT(t)
			//			end
			for (var t = dt; t <= ft - dt; t+=dt)
			{
				sum		=	sum	+	this.getPrimeT(t) ;
			}
			
			return sum/n + sum1 ;
			
		}
		
		public function render(rHelper:RenderHelper) : void
		{
			rHelper.drawCircle(this._cp0.X(),this._cp0.Y(),10) ;
			rHelper.drawCircle(this._cp1.X(),this._cp1.Y(),10) ;
			rHelper.drawCircle(this._cp2.X(),this._cp2.Y(),10) ;
			rHelper.drawCircle(this._cp3.X(),this._cp3.Y(),10) ;
			
			for (var t = 0 ; t <= 1 ; t+=0.01)
			{
				var pos = this.getVectorPosition(t)
				rHelper.drawCircle(pos.x,pos.y,1) ;
			}
		},
		

		
		

		
		
		
	}
}